﻿using System;
using System.IO;
using System.IO.IsolatedStorage;
using System.Windows;
using System.Windows.Media.Imaging;

namespace Store.WP7.Framework.Extensions
{
    /// <summary>
    ///     Provides some extension methods to work with IsolatedStorageFile
    /// </summary>
    public static class IsolatedStorageFileEx
    {
        /// <summary>
        ///     Saves a binary file in the isolated storage
        /// </summary>
        /// <param name="isolatedStorageFile"></param>
        /// <param name="fileContent"></param>
        /// <param name="path"></param>
        /// <param name="overrideFile"></param>
        public static void SaveFile(this IsolatedStorageFile isolatedStorageFile, byte[] fileContent, string path, bool overrideFile = true)
        {
            CreateDirectoryIfNotExists(isolatedStorageFile, path);

            if (isolatedStorageFile.FileExists(path) && !overrideFile)
                return;

            using (var fileStream = isolatedStorageFile.OpenFile(path, FileMode.OpenOrCreate, FileAccess.Write))
            {
                fileStream.Write(fileContent, 0, fileContent.Length);
            }
        }

        /// <summary>
        ///     Saves a text file in the isolated storage
        /// </summary>
        /// <param name="isolatedStorageFile"></param>
        /// <param name="contentText"></param>
        /// <param name="path"></param>
        /// <param name="overrideFile"></param>
        public static void SaveFile(this IsolatedStorageFile isolatedStorageFile, string contentText, string path, bool overrideFile = true)
        {
            CreateDirectoryIfNotExists(isolatedStorageFile, path);
            if (isolatedStorageFile.FileExists(path) && !overrideFile)
                return;

            using (var fileStream = isolatedStorageFile.OpenFile(path, FileMode.OpenOrCreate, FileAccess.Write))
            {
                using (var streamWriter = new StreamWriter(fileStream))
                {
                    streamWriter.Write(contentText);
                }
            }
        }

        /// <summary>
        ///     Saves a file in the isolated storage from a stream
        /// </summary>
        /// <param name="isolatedStorageFile"></param>
        /// <param name="streamToSave"></param>
        /// <param name="path"></param>
        /// <param name="overrideFile"></param>
        public static void SaveFile(this IsolatedStorageFile isolatedStorageFile, Stream streamToSave, string path, bool overrideFile = true)
        {
            byte[] buffer = new byte[streamToSave.Length];
            streamToSave.Read(buffer, 0, buffer.Length);

            isolatedStorageFile.SaveFile(buffer, path, overrideFile);
        }

        /// <summary>
        ///     Saves a picture in the isolated storage, created from a UIElement
        /// </summary>
        /// <param name="isolatedStorageFile"></param>
        /// <param name="element"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="path"></param>
        /// <param name="overrideFile"></param>
        public static void SavePictureFromUIElement(this IsolatedStorageFile isolatedStorageFile, UIElement element, int width, int height, string path, bool overrideFile = true)
        {
            CreateDirectoryIfNotExists(isolatedStorageFile, path);

            element.Measure(new Size(width, height));
            element.Arrange(new Rect(0, 0, width, height));
            element.UpdateLayout();

            WriteableBitmap wb = new WriteableBitmap(width, height);
            wb.Render(element, null);
            wb.Invalidate();
            

            using (var fileStream = isolatedStorageFile.OpenFile(path, FileMode.OpenOrCreate, FileAccess.Write))
            {
                wb.SaveJpeg(fileStream, width, height, 0, 100);
            }
        }

        /// <summary>
        ///     Gets the binary content of a given file
        /// </summary>
        /// <param name="isolatedStorageFile"></param>
        /// <param name="path"></param>
        /// <returns></returns>
        public static byte[] GetFileContent(this IsolatedStorageFile isolatedStorageFile, string path)
        {
            if (!isolatedStorageFile.FileExists(path))
                throw new FileNotFoundException(string.Format("The file '{0}' was not found", path));

            using (var fileStream = isolatedStorageFile.OpenFile(path, FileMode.Open, FileAccess.Read))
            {
                byte[] buffer = new byte[fileStream.Length];
                fileStream.Read(buffer, 0, buffer.Length);
                return buffer;
            }
        }

        /// <summary>
        ///     Gets a BitmapSource from a file
        /// </summary>
        /// <param name="isolatedStorageFile"></param>
        /// <param name="path"></param>
        /// <remarks>The method should be call in the Dispatcher thread</remarks>
        /// <returns></returns>
        public static BitmapSource GetBitmapSourceFromFile(this IsolatedStorageFile isolatedStorageFile, string path)
        {
            if (!Deployment.Current.Dispatcher.CheckAccess())
                throw new InvalidOperationException("This method should be called in the Dispatcher thread!");

            byte[] imageBytes = isolatedStorageFile.GetFileContent(path);
            BitmapSource bitmapSource = new BitmapImage();
            bitmapSource.SetSource(new MemoryStream(imageBytes));
            return bitmapSource;
        }

        /// <summary>
        ///     Gets the content of a given text file
        /// </summary>
        /// <param name="isolatedStorageFile"></param>
        /// <param name="path"></param>
        /// <returns></returns>
        public static string ReadFile(this IsolatedStorageFile isolatedStorageFile, string path)
        {
            if (!isolatedStorageFile.FileExists(path))
                throw new FileNotFoundException(string.Format("The file '{0}' was not found", path));

            using (var fileStream = isolatedStorageFile.OpenFile(path, FileMode.Open, FileAccess.Read))
            {
                using (var streamReader = new StreamReader(fileStream))
                {
                    return streamReader.ReadToEnd();
                }
            }
        }

        /// <summary>
        ///     Creates a directory if it does not exist
        /// </summary>
        /// <param name="isolatedStorageFile"></param>
        /// <param name="path"></param>
        private static void CreateDirectoryIfNotExists(IsolatedStorageFile isolatedStorageFile, string path)
        {
            string directory = System.IO.Path.GetDirectoryName(path);
            if (!isolatedStorageFile.DirectoryExists(directory))
            {
                isolatedStorageFile.CreateDirectory(directory);
            }
        }
    }
}
